package cn.edu.lzzy.mypractices.service;

import cn.edu.lzzy.mypractices.constant.Messages;
import cn.edu.lzzy.mypractices.entity.Chapter;
import cn.edu.lzzy.mypractices.entity.Option;
import cn.edu.lzzy.mypractices.entity.Question;
import cn.edu.lzzy.mypractices.repository.OptionRepository;
import cn.edu.lzzy.mypractices.repository.QuestionRepository;
import cn.edu.lzzy.mypractices.util.AuthUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

@Service
public class QuestionServiceImpl implements QuestionService {

    private final QuestionRepository questionRepository;
    private final OptionRepository optionRepository;

    public QuestionServiceImpl(QuestionRepository questionRepository, OptionRepository optionRepository) {
        this.questionRepository = questionRepository;
        this.optionRepository = optionRepository;
    }

    @Cacheable(value = "questions", key = "#chapter.id.toString()")
    @Override
    public List<Question> getAllByChapter(Chapter chapter) {
        return questionRepository.findAllByChapter(chapter);
    }
    @Cacheable(value = "questions", key = "#uuid.toString()")
    @Override
    public List<Question> getAllByChapter(UUID uuid) {
        return questionRepository.findAllByChapterId(uuid);
    }

    @Cacheable(value = "pagedQuestions", key = "#chapter.id.toString() + '_' + page + '_' + size")
    @Override
    public List<Question> getAllByChapter(Chapter chapter, int page, int size) {
        return questionRepository.findAllByChapter(chapter, PageRequest.of(page, size));
    }

    @Cacheable(value = "pagedQuestions", key = "#uuid.toString() + '_' + page + '_' + size")
    @Override
    public List<Question> getAllByChapter(UUID uuid, int page, int size) {
        return questionRepository.findAllByChapterId(uuid, PageRequest.of(page, size));
    }

    @Cacheable(value = "questionById", key = "#uuid.toString()")
    @Override
    public Question getByQuestionId(UUID uuid) {
        return questionRepository.findById(uuid).orElse(null);
    }

    @Cacheable(value = "questionCount", key = "#chapter.id.toString()")
    @Override
    public int count(Chapter chapter) {
        return questionRepository.countAllByChapter(chapter);
    }

    @Cacheable(value = "questionCount", key = "#chapter_id.toString()")
    @Override
    public int count(UUID chapter_id) {
        return questionRepository.countAllByChapterId(chapter_id);
    }

    @Caching(put = {
            @CachePut(value = "questionById", key = "#questionIn.id.toString()")
    }, evict = {
            @CacheEvict(value = "questions", key = "#questionIn.chapter.id.toString()"),
            @CacheEvict(value = "pagedQuestions", allEntries = true),
            @CacheEvict(value = "questionCount", allEntries = true)
    })
    @Override
    public Question addQuestion(Question questionIn) {
        return questionRepository.save(questionIn);
    }

    @Caching(put = {
            @CachePut(value = "questionById", key = "#questionIn.id.toString()")
    }, evict = {
            @CacheEvict(value = "questions", key = "#questionIn.chapter.id.toString()"),
            @CacheEvict(value = "pagedQuestions", allEntries = true),
            @CacheEvict(value = "questionCount", allEntries = true)
    })
    @Override
    public Question updateQuestion(Question questionIn) {
        return questionRepository.save(questionIn);
    }

    // 移除问题
    @Caching(evict = {
            @CacheEvict(value = "questionById", key = "#questionIn.toString()"),
            @CacheEvict(value = "questions", allEntries = true),
            @CacheEvict(value = "pagedQuestions", allEntries = true),
            @CacheEvict(value = "questionCount", allEntries = true),

            // 选项部分
            @CacheEvict(value = "optionById", allEntries = true),
            @CacheEvict(value = "options", allEntries = true)
    })
    @Override
    public Messages removeQuestion(UUID questionIn, String token) {
        Question question = questionRepository.findById(questionIn).orElse(null);
        if (question == null) {
            return Messages.WRONG_ID;
        }

        UUID teacherId = question.getChapter().getCourse().getTeacher().getId();
        if (AuthUtils.invalid(teacherId, token)) {
            return Messages.NO_PERMISSION;
        }

        // 因为外键限制 必须得先清空选项
        List<Option> options = optionRepository.findAllByQuestion(question);
        if (options.size() > 0) {
            System.out.println("delete all");
            optionRepository.deleteAll(options);
        }

        questionRepository.delete(question);
        return Messages.SUCCESS;
    }

    // 获取问题下的所有选项
    @Cacheable(value = "options", key = "#question.id.toString()")
    @Override
    public List<Option> getAllByQuestion(Question question) {
        return optionRepository.findAllByQuestion(question);
    }

    @Cacheable(value = "options", key = "#uuid.toString()")
    @Override
    public List<Option> getAllByQuestion(UUID uuid) {
        return optionRepository.findAllByQuestionId(uuid);
    }

    // 通过选项ID获取选项实例
    @Cacheable(value = "optionById", key = "#uuid.toString()")
    @Override
    public Option getByOptionId(UUID uuid) {
        return optionRepository.findById(uuid).orElse(null);
    }

    @Caching(put = {
            @CachePut(value = "optionById", key = "#option.id.toString()")
    }, evict = {
            @CacheEvict(value = "options", key = "#option.id.toString()")
    })
    @Override
    public Option addOption(Option option) {
        return optionRepository.save(option);
    }

    @Caching(put = {
            @CachePut(value = "optionById", key = "#option.id.toString()")
    }, evict = {
            @CacheEvict(value = "options", key = "#option.id.toString()")
    })
    @Override
    public Option updateOption(Option option) {
        return optionRepository.save(option);
    }

    @Caching(evict = {
            @CacheEvict(value = "optionById", key = "#optionIn.toString()"),
            @CacheEvict(value = "options", key = "#optionIn.toString()")
    })
    @Override
    public Messages removeOption(UUID optionIn, String token) {
        Option option = optionRepository.findById(optionIn).orElse(null);
        if (option == null) {
            return Messages.WRONG_ID;
        }

        UUID teacherId = option.getQuestion().getChapter().getCourse().getTeacher().getId();
        if (AuthUtils.invalid(teacherId, token)) {
            return Messages.NO_PERMISSION;
        }

        optionRepository.delete(option);
        return Messages.SUCCESS;
    }
}
